import numpy as np
import matplotlib.pyplot as plt
from sklearn.metrics import mean_squared_error
from sklearn.model_selection import train_test_split

# 初始化设置
plt.rcParams['font.sans-serif'] = ['KaiTi']  # 中文字体
plt.rcParams['mathtext.fontset'] = 'stix'     # 数学字体
plt.rcParams['axes.unicode_minus'] = False


# ==================== 数据准备阶段 ====================
# 设置随机种子保证结果可复现
np.random.seed(42)

# 生成特征数据X：100个样本，1个特征，取值范围[0,2)
X = 2 * np.random.rand(100, 1)

# 生成标签数据：真实模型为 y = 4 + 3X + 噪声
# 其中4是截距(bias term)，3是权重系数(weight)
# 噪声服从标准正态分布 N(0,1)
y = 4 + 3 * X + np.random.randn(100, 1)

# 划分训练集和测试集 (80%训练，20%测试)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)



from sklearn.linear_model import SGDRegressor
from sklearn.preprocessing import StandardScaler

# ==================== 数据标准化 ====================
# SGD对特征缩放敏感，建议进行标准化
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

# ==================== SGD回归模型 ====================
# 创建SGD回归模型
# penalty='l2': 使用L2正则化(等同于岭回归)
# max_iter: 最大迭代次数
# eta0: 初始学习率
# random_state: 随机种子
sgd_reg = SGDRegressor(
    penalty='l2',
    alpha=0.4,  # 正则化系数
    max_iter=10000,
    eta0=0.01,
    random_state=42
)

# 训练模型 (注意y需要ravel()转换为一维数组)
sgd_reg.fit(X_train_scaled, y_train.ravel())

# ==================== 模型评估 ====================
# 训练集预测
y_train_pred_sgd = sgd_reg.predict(X_train_scaled)
train_mse_sgd = mean_squared_error(y_train, y_train_pred_sgd)

# 测试集预测
y_test_pred_sgd = sgd_reg.predict(X_test_scaled)
test_mse_sgd = mean_squared_error(y_test, y_test_pred_sgd)

# ==================== 结果输出 ====================
print("\n===== SGD回归结果 =====")
print(f"截距项(w0): {sgd_reg.intercept_[0]:.4f}")
print(f"系数(w1): {sgd_reg.coef_[0]:.4f}")
print(f"训练集MSE: {train_mse_sgd:.4f}")
print(f"测试集MSE: {test_mse_sgd:.4f}")

# ==================== 可视化 ====================
plt.figure(figsize=(12, 6))

# 绘制训练数据
plt.scatter(X_train, y_train, color='blue', label='训练数据', alpha=0.6)

# 绘制测试数据
plt.scatter(X_test, y_test, color='green', label='测试数据', alpha=0.6)

# 绘制拟合线
X_plot = np.linspace(0, 2, 100).reshape(-1, 1)

X_plot_scaled = scaler.transform(X_plot)
y_plot_sgd = sgd_reg.predict(X_plot_scaled)
plt.plot(X_plot, y_plot_sgd, color='purple', linewidth=2, label='SGD回归拟合线')

plt.title('SGD回归示例 (L2正则化)', fontsize=14)
plt.xlabel('X特征值', fontsize=12)
plt.ylabel('y标签值', fontsize=12)
plt.legend(fontsize=10)
plt.grid(True)
plt.show()
